<?php

namespace app\api\controller;

use app\admin\model\Xcx;
use think\Exception;
use think\exception\HttpResponseException;
use think\Request;
use think\Response;
use think\Cache;

/**
 * API控制器基类
 */
class Base
{
    /**
     * @var Request Request 实例
     */
    protected $request;

    /**
     * 默认响应输出类型,支持json/xml
     * @var string
     */
    protected $responseType = 'json';

    /**
     * 构造方法
     * @access public
     * @param Request $request Request 对象
     */
    public function __construct(Request $request = null)
    {
        $this->request = is_null($request) ? Request::instance() : $request;
    }

    /**
     * 检测当前控制器和方法是否匹配传递的数组
     *
     * @param array $arr 需要验证权限的数组
     * @return boolean
     */
    public function match($arr = [], $actionname)
    {
        $arr = is_array($arr) ? $arr : explode(',', $arr);
        if (!$arr) {
            return FALSE;
        }
        $arr = array_map('strtolower', $arr);
        // 是否存在
        if (in_array(strtolower($actionname), $arr) || in_array('*', $arr)) {
            return TRUE;
        }

        // 没找到匹配
        return FALSE;
    }

    /**
     * 操作成功返回的数据
     * @param string $msg   提示信息
     * @param mixed $data   要返回的数据
     * @param int   $code   错误码，默认为1
     * @param string $type  输出类型
     * @param array $header 发送的 Header 信息
     */
    protected function success($msg = '', $data = null, $code = 1, $type = null, array $header = [])
    {
        $this->result($msg, $data, $code, $type, $header);
    }

    /**
     * 操作失败返回的数据
     * @param string $msg   提示信息
     * @param mixed $data   要返回的数据
     * @param int   $code   错误码，默认为0
     * @param string $type  输出类型
     * @param array $header 发送的 Header 信息
     */
    protected function error($msg = '', $data = null, $code = 0, $type = null, array $header = [])
    {
        $this->result($msg, $data, $code, $type, $header);
    }

    /**
     * 返回封装后的 API 数据到客户端
     * @access protected
     * @param mixed  $msg    提示信息
     * @param mixed  $data   要返回的数据
     * @param int    $code   错误码，默认为0
     * @param string $type   输出类型，支持json/xml/jsonp
     * @param array  $header 发送的 Header 信息
     * @return void
     * @throws HttpResponseException
     */
    protected function result($msg, $data = null, $code = 0, $type = null, array $header = [])
    {
        $result = [
            'code' => $code,
            'msg'  => $msg,
            'time' => Request::instance()->server('REQUEST_TIME'),
            'data' => $data,
        ];
        // 如果未设置类型则自动判断
        $type = $type ? $type : ($this->request->param(config('var_jsonp_handler')) ? 'jsonp' : $this->responseType);

        if (isset($header['statuscode']))
        {
            $code = $header['statuscode'];
            unset($header['statuscode']);
        }
        else
        {
            //未设置状态码,根据code值判断
            $code = $code >= 1000 || $code < 200 ? 200 : $code;
        }
        $response = Response::create($result, $type, $code)->header($header);
        throw new HttpResponseException($response);
    }

    /**
     * 发送http请求方法
     * @param string  $url      请求URL
     * @param array   $params   请求参数
     * @param string  $method   请求方法GET/POST
     * @param array   $header   请求头
     * @return array  $data     响应数据
     * @throws Exception
     */
    protected function http($url, $params = [], $method = 'GET', $header = array(), $multi = false)
    {
        $opts = array(
            CURLOPT_TIMEOUT => 30,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_HTTPHEADER => $header
        );
        /* 根据请求类型设置特定参数 */
        switch (strtoupper($method)) {
            case 'GET':
                if (empty($params)) {
                    $opts[CURLOPT_URL] = $url;
                } else {
                    $opts[CURLOPT_URL] = $url . '?' . http_build_query($params);
                }
                break;
            case 'POST':
                // 判断是否传输文件
//                $params = $multi ? $params : http_build_query($params);
                $opts[CURLOPT_URL] = $url;
                $opts[CURLOPT_POST] = 1;
                $opts[CURLOPT_POSTFIELDS] = $params;
                break;
            default:
                throw new Exception('不支持的请求方式');
        }
        /* 初始化并执行curl请求 */
        $ch = curl_init();
        curl_setopt_array($ch, $opts);
        $data = curl_exec($ch);
        $error = curl_error($ch);
        curl_close($ch);
        if ($error) throw new Exception('请求发生错误; ' . $error);
        return $data;
    }

    /**
     * 获取openid
     * @param $gh_id
     * @param $code
     * @return bool|mixed
     * @throws Exception
     * @throws \think\exception\DbException
     */
    protected function get_openid($gh_id, $code)
    {
        $xcx = Xcx::get(['ghid' => $gh_id]);

        $url = 'https://api.weixin.qq.com/sns/jscode2session';
        $params['appid'] = $xcx['appid'];
        $params['secret'] = $xcx['secret'];
        $params['js_code'] = $code;
        $params['grant_type'] = 'authorization_code';

        // 请求微信后台获取openid
        $res = $this->http($url, $params);
        $data = json_decode($res, true);
        if (array_key_exists('openid', $data)) {
            return $data['openid'];
        } else {
            return false;
        }
    }

    // 向微信服务器获取openid和session
    protected function jscode2session($gh_id, $code)
    {
        $xcx = Xcx::get(['ghid' => $gh_id]);
        $url = 'https://api.weixin.qq.com/sns/jscode2session';
        $params['appid'] = $xcx['appid'];
        $params['secret'] = $xcx['secret'];
        $params['js_code'] = $code;
        $params['grant_type'] = 'authorization_code';

        // 请求微信后台获取openid
        $res = $this->http($url, $params);
        $data = json_decode($res, true);
        if (array_key_exists('openid', $data)) {
            return $data;
        } else {
            return false;
        }
    }

    // 获取签到条件json(缓存)
    protected function get_json_file($key, $file_name, $cache = false)
    {
        if ($cache) {
            $list = json_decode(file_get_contents(ROOT_PATH . 'public/assets/json/' . $file_name . '.json'));
            Cache::set($key, $list);
        } else {
            $list = Cache::get($key);
            if (!$list) {
                $list = json_decode(file_get_contents(ROOT_PATH . 'public/assets/json/' . $file_name . '.json'));
                Cache::set($key, $list);
            }
        }
        return $list;
    }

    // 对比版本号
    public function compare_version($v1, $v2)
    {
        $v1 = explode('.', $v1);
        $v2 = explode('.', $v2);
        $len = max(count($v1), count($v2));
        if (count($v1) < $len) {
            array_push($v1, 0);
        }
        if (count($v2) < $len) {
            array_push($v2, 0);
        }
        for ($i = 0; $i < $len; $i++) {
            $n1 = intval($v1[$i]);
            $n2 = intval($v2[$i]);
            if ($n1 > $n2) return 1;
            if ($n1 < $n2) return -1;
        }
        return 0;
    }
}
